/**
 * @file storage_manager.cpp
 * @brief 存储管理器实现
 */

#include "storage_manager.h"
#include "sysconfig.h"
#include "logger.hpp"
#include "hash_util.h"
#include "id_generator.h"
#include <filesystem>
#include <fstream>
#include <ctime>
#include <iomanip>
#include <sstream>

/**
 * @brief 获取单例实例
 */
StorageManager& StorageManager::getInstance() 
{
    static StorageManager instance;
    return instance;
}

/**
 * @brief 析构函数
 */
StorageManager::~StorageManager() 
{
    cleanup();
}

/**
 * @brief 初始化存储管理器
 */
bool StorageManager::init() 
{
    std::lock_guard<std::mutex> lock(mutex_);
    
    if (initialized_) 
    {
        return true;
    }
    
    // 检查存储目录是否存在
    const std::string& storage_root = Config::getStorageRoot();
    if (!std::filesystem::exists(storage_root)) 
    {
        Log::GetLogger("asynclogger")->Info("存储根目录不存在: %s", storage_root.c_str());
        return false;
    }
    
    // 检查临时目录
    const std::string& temp_dir = Config::getTempDir();
    if (!std::filesystem::exists(temp_dir)) 
    {
        Log::GetLogger("asynclogger")->Info("临时目录不存在: %s", temp_dir.c_str());
        return false;
    }
    
    initialized_ = true;
    Log::GetLogger("asynclogger")->Info("存储管理器初始化成功");
    return true;
}

/**
 * @brief 清理资源
 */
void StorageManager::cleanup() 
{
    std::lock_guard<std::mutex> lock(mutex_);
    initialized_ = false;
}

/**
 * @brief 保存上传的文件
 */
UploadResult StorageManager::saveUploadedFile(const std::string& temp_file_path, 
                                            const std::string& original_filename,
                                            const std::string& mime_type) 
{
    UploadResult result;
    result.success = false;
    result.is_duplicate = false;
    
    // 检查临时文件是否存在
    if (!std::filesystem::exists(temp_file_path)) 
    {
        result.error_msg = "临时文件不存在";
        return result;
    }
    
    // 获取文件大小
    std::error_code ec;
    result.filesize = std::filesystem::file_size(temp_file_path, ec);
    if (ec) 
    {
        result.error_msg = "无法获取文件大小";
        return result;
    }
    
    // 检查文件大小限制
    if (result.filesize > Config::getMaxFileSize()) 
    {
        result.error_msg = "文件大小超过限制";
        return result;
    }
    
    // 计算文件哈希值
    result.hash = HashUtil::calculateFileSHA256(temp_file_path);
    if (result.hash.empty()) 
    {
        result.error_msg = "计算文件哈希失败";
        return result;
    }
    
    auto& db = DatabaseManager::getInstance();
    
    // 检查是否为重复文件
    FileInfo existing_file;
    if (db.getFileByHash(result.hash, existing_file)) 
    {
        // 文件已存在，返回现有ID
        result.success = true;
        result.file_id = existing_file.id;
        result.is_duplicate = true;
        
        // 删除临时文件
        std::filesystem::remove(temp_file_path, ec);
        
        Log::GetLogger("asynclogger")->Info("发现重复文件，返回现有ID: %s", result.file_id.c_str());
        return result;
    }
    
    // 生成唯一文件ID
    result.file_id = IdGenerator::generateUniqueId(result.hash);
    if (result.file_id.empty()) 
    {
        result.error_msg = "生成文件ID失败";
        return result;
    }
    
    // 生成存储路径
    std::string extension = getFileExtension(original_filename);
    std::string storage_path = generateStoragePath(result.hash, extension);
    
    // 移动文件到存储位置
    if (!moveToStorage(temp_file_path, storage_path)) 
    {
        result.error_msg = "移动文件到存储位置失败";
        return result;
    }
    
    // 保存文件信息到数据库
    FileInfo file_info;
    file_info.id = result.file_id;
    file_info.hash = result.hash;
    file_info.filename = original_filename;
    file_info.filesize = result.filesize;
    file_info.mime_type = mime_type;
    file_info.upload_time = getCurrentTimestamp();
    file_info.download_count = 0;
    
    if (!db.insertFile(file_info)) 
    {
        // 插入数据库失败，删除已保存的文件
        std::filesystem::remove(storage_path, ec);
        result.error_msg = "保存文件信息到数据库失败";
        return result;
    }
    
    result.success = true;
    Log::GetLogger("asynclogger")->Info("文件保存成功: ID=%s, Hash=%s, Size=%llu", result.file_id.c_str(), result.hash.c_str(), result.filesize);
    
    return result;
}

/**
 * @brief 根据文件ID获取文件路径
 */
std::string StorageManager::getFilePath(const std::string& file_id) 
{
    auto& db = DatabaseManager::getInstance();
    FileInfo file_info;
    
    if (!db.getFileById(file_id, file_info)) 
    {
        return "";
    }
    
    std::string extension = getFileExtension(file_info.filename);
    return generateStoragePath(file_info.hash, extension);
}

/**
 * @brief 根据文件ID获取文件信息
 */
bool StorageManager::getFileInfo(const std::string& file_id, FileInfo& file_info) 
{
    auto& db = DatabaseManager::getInstance();
    return db.getFileById(file_id, file_info);
}

/**
 * @brief 删除文件
 */
bool StorageManager::deleteFile(const std::string& file_id) 
{
    std::string file_path = getFilePath(file_id);
    if (file_path.empty()) {
        return false;
    }
    
    std::error_code ec;
    return std::filesystem::remove(file_path, ec);
}

/**
 * @brief 检查文件是否存在
 */
bool StorageManager::fileExists(const std::string& file_id) 
{
    std::string file_path = getFilePath(file_id);
    if (file_path.empty()) {
        return false;
    }
    
    return std::filesystem::exists(file_path);
}

/**
 * @brief 更新文件下载计数
 */
bool StorageManager::updateDownloadCount(const std::string& file_id) 
{
    auto& db = DatabaseManager::getInstance();
    return db.updateDownloadCount(file_id);
}

/**
 * @brief 清理临时文件
 */
int StorageManager::cleanupTempFiles(int max_age_hours) 
{
    const std::string& temp_dir = Config::getTempDir();
    int count = 0;
    
    try 
    {
        auto now = std::filesystem::file_time_type::clock::now();
        auto max_age = std::chrono::hours(max_age_hours);
        
        for (const auto& entry : std::filesystem::directory_iterator(temp_dir)) 
        {
            if (entry.is_regular_file()) {
                auto file_time = entry.last_write_time();
                if (now - file_time > max_age) 
                {
                    std::error_code ec;
                    if (std::filesystem::remove(entry.path(), ec)) 
                    {
                        count++;
                        Log::GetLogger("asynclogger")->Info("清理过期临时文件: %s", entry.path().c_str());
                    }
                }
            }
        }
    } 
    catch (const std::exception& e) 
    {
        Log::GetLogger("asynclogger")->Info("清理临时文件失败: %s", e.what());
    }
    
    if (count > 0) 
    {
        Log::GetLogger("asynclogger")->Info("清理了 %d 个过期临时文件", count);
    }
    
    return count;
}

/**
 * @brief 根据哈希值生成文件存储路径
 */
std::string StorageManager::generateStoragePath(const std::string& hash, const std::string& extension) 
{
    if (hash.length() < 2) 
    {
        return "";
    }
    
    // 使用哈希值前2位作为子目录
    std::string subdir = hash.substr(0, 2);
    std::string filename = hash + extension;
    
    return Config::getStorageRoot() + "/files/" + subdir + "/" + filename;
}

/**
 * @brief 移动文件到最终存储位置
 */
bool StorageManager::moveToStorage(const std::string& temp_path, const std::string& storage_path) 
{
    try 
    {
        // 确保目标目录存在
        std::filesystem::path storage_dir = std::filesystem::path(storage_path).parent_path();
        std::filesystem::create_directories(storage_dir);
        
        // 移动文件
        std::error_code ec;
        std::filesystem::rename(temp_path, storage_path, ec);
        
        if (ec) 
        {
            // 如果重命名失败，尝试复制并删除原文件
            Log::GetLogger("asynclogger")->Info("文件重命名失败，尝试复制: %s", ec.message().c_str());
            
            std::filesystem::copy_file(temp_path, storage_path, ec);
            if (ec) 
            {
                Log::GetLogger("asynclogger")->Info("文件复制失败: %s", ec.message().c_str());
                return false;
            }
            
            std::filesystem::remove(temp_path, ec);
            if (ec) 
            {
                Log::GetLogger("asynclogger")->Info("删除临时文件失败: %s", ec.message().c_str());
            }
        }
        
        return true;
        
    } 
    catch (const std::exception& e) 
    {
        Log::GetLogger("asynclogger")->Info("移动文件到存储位置失败: %s", e.what());
        return false;
    }
}

/**
 * @brief 从文件名提取扩展名
 */
std::string StorageManager::getFileExtension(const std::string& filename) 
{
    size_t pos = filename.find_last_of('.');
    if (pos != std::string::npos && pos < filename.length() - 1) 
    {
        return filename.substr(pos);
    }
    return "";
}

/**
 * @brief 获取当前时间戳字符串
 */
std::string StorageManager::getCurrentTimestamp() 
{
    auto now = std::time(nullptr);
    auto tm = *std::gmtime(&now);
    
    std::ostringstream oss;
    oss << std::put_time(&tm, "%Y-%m-%d %H:%M:%S");
    return oss.str();
} 